package com.hy.mvc.web.inteceptor;

import com.hy.mvc.biz.service.common.support.PageContext;
import com.hy.mvc.biz.service.common.support.UserContext;
import com.hy.mvc.domain.dataobject.entity.User;
import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Set;

/**
 * <pre>
 *    author  : Booker
 *    time    : 2017/12/4 14:59
 *    desc    : 类似于Servlet开发中的过滤器Filter，用于对处理器进行预处理和后处理。
 *    5.1.1、常见应用场景
 * 1、日志记录：记录请求信息的日志，以便进行信息监控、信息统计、计算PV（Page View）等。
 * 2、权限检查：如登录检测，进入处理器检测检测是否登录，如果没有直接返回到登录页面；
 * 3、性能监控：有时候系统在某段时间莫名其妙的慢，可以通过拦截器在进入处理器之前记录开始时间，在处理完后记录结束时间，从而得到该请求的处理时间（如果有反向代理，如apache可以自动记录）；
 * 4、通用行为：读取cookie得到用户信息并将用户对象放入请求，从而方便后续流程使用，还有如提取Locale、Theme信息等，只要是多个处理器都需要的即可使用拦截器实现。
 * 5、OpenSessionInView：如Hibernate，在进入处理器打开Session，在完成后关闭Session。
 * …………本质也是AOP（面向切面编程），也就是说符合横切关注点的所有功能都可以放入拦截器实现
 *    version : v1.0
 * </pre>
 */
public class LoginInterceptor implements HandlerInterceptor {
    ThreadLocal<Long> startTime = new ThreadLocal<>();
    private Logger logger = Logger.getLogger(getClass());
    private Set<String> allowUrl;

    private Set<String> forbiddenURl;

    /**
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @return preHandle：预处理回调方法，实现处理器的预处理（如登录检查），第三个参数为响应的处理器（如我们上一章的Controller实现）； 返回值：true表示继续流程（如调用下一个拦截器或处理器）；
     * false表示流程中断（如登录检查失败），不会继续调用其他的拦截器或处理器，此时我们需要通过response来产生响应；
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        startTime.set(System.currentTimeMillis());
        logger.info("startTime**************************" + startTime.get());
        httpServletRequest.setAttribute("Booker", startTime.get());
        User user = new User();
        user.setUserName("test123465");
        BeanUtils.copyProperties(user, UserContext.current());
        PageContext.current().setRequest(httpServletRequest);
        return true;
    }

    /**
     * postHandle：后处理回调方法，实现处理器的后处理（但在渲染视图之前），此时我们可以通过
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    /**
     * afterCompletion：整个请求处理完毕回调方法，即在视图渲染完毕时回调，如性能监控中我们可以在此记录结束时间并输出消耗时间，还可以进行一些资源清理，类似于try-catch-finally中的finally，但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param e
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        Long endTime = System.currentTimeMillis();
        logger.info("计算时间为:" + (endTime - startTime.get()) + "ms");
//        System.out.println("request is*******************" + httpServletRequest.getAttribute("Booker"));
    }


    public Set<String> getAllowUrl() {
        return allowUrl;
    }

    public void setAllowUrl(Set<String> allowUrl) {
        this.allowUrl = allowUrl;
    }

    public Set<String> getForbiddenURl() {
        return forbiddenURl;
    }

    public void setForbiddenURl(Set<String> forbiddenURl) {
        this.forbiddenURl = forbiddenURl;
    }
}
